package com.cellngine.server;

import java.net.*;
import java.util.HashMap;
import java.io.*;

import com.cellngine.Constants;
import com.cellngine.JO;
import com.cellngine.Cellngine;

public class ServerClientSocket extends Thread
{
	private final Socket		socket;
	public final ServerManager	master;
	public final String			ip;
	private InputStream			inputStream;
	private OutputStream		outputStream;
	
	public ServerClientSocket(final ServerManager master, final Socket socket)
	{
		this.ip = ((InetSocketAddress) socket.getLocalSocketAddress()).getAddress()
				.getHostAddress();
		this.socket = socket;
		this.master = master;
	}
	
	@Override
	public void run()
	{
		//TODO: Determine the type of client better (one byte doesn't cut it...) and if it's a valid cellngine client keep the connection open and start pulling in data. -JB
		try
		{
			this.inputStream = this.socket.getInputStream();
			this.outputStream = this.socket.getOutputStream();
			/*"real" clients identify themselves by sending a 0x01 byte.
			 * If a client wants information about the server in an XML format, it should send a
			 * 0x00 byte.
			 * If anything else is sent to the server, it will print out a human-readable copy
			 * of basic information about the server (whether or not a password is required
			 * etc.)
			 */

			final byte[] buffer;
			final int inputChar = this.inputStream.read();
			
			if (inputChar == 1)
			{
				//'Real' clients
				//TODO: Receive basic information from the client (i.e., which version of cellngine?) -JB
				
				//TODO: Act on above information (i.e., reject clients who have older versions) -JB
				
				//TODO: Send basic server information to the client (server motd/news, skin information) -JB
				
				//TODO: Wait for the client to send more & act on this information. -JB
			}
			else if (inputChar == 0)
			{
				//TODO: Return information about this server in XML format and close the connection. -JB
			}
			else
			{
				//TODO: Return information about this server in plain-text and close the connection. -JB
				//Potentially also allow HTTP access to this server which returns the result in HTML.
			}
			
			/*
			if (inputChar == 1)
			{
				this.send((char) 1 + "");
			}
			else if (inputChar == 0)
			{
				this.sendInfoXML();
				return;
			}
			else
			{
				this.sendInfoPlainText();
				return;
			}
			*/
		}
		catch (final Exception e)
		{
			Cellngine.log(e, Constants.log_type.error);
		}
		this.close();
	}
	
	private void sendInfoXML()
	{
		final HashMap<String, String> serverInfos = new HashMap<String, String>();
		serverInfos.put("PasswordEnabled", this.master.passwordEnabled() ? "true" : "false");
		serverInfos.put("MaxPlayers", this.master.getMaxPlayers() + "");
		serverInfos.put("ConnectionsPerClient", Constants.connections_per_client + "");
		serverInfos.put("SocketTimeout", Constants.socket_timeout_ms + "");
		serverInfos.put("UsesHub", (this.master.isHubRegistered() ? "true" : "false") + "");
		serverInfos.put("HubURL", this.master.hubURL());
		this.send(JO.hashmapToXML(serverInfos));
		this.close();
	}
	
	private void sendInfoPlainText()
	{
		this.send("--- Server details ---\r\n");
		this.send("cellngine version: " + Constants.VERSION_MAJOR + "." + Constants.VERSION_MINOR
				+ " R" + Constants.VERSION_REVISION + "\r\n");
		this.send("Password required: " + (this.master.passwordEnabled() ? "yes" : "no") + "\r\n");
		this.send("Maximum player number: " + this.master.getMaxPlayers() + "\r\n");
		this.send("Hub secured: " + (this.master.isHubRegistered() ? "yes" : "no") + "\r\n");
		this.close();
	}
	
	/**
	 * Sends a raw <code>String</code> to the client by writing it into and flushing the output
	 * buffer.
	 * 
	 * @param string
	 *            The <code>String</code> which shall be sent
	 * @return <code>true</code> if sending the <code>String</code> succeeded, otherwise
	 *         <code>false</code>.
	 */
	public synchronized boolean send(final String string)
	{
		try
		{
			for (int i = 0; i < string.length(); i++)
			{
				this.outputStream.write(string.charAt(i));
			}
			this.outputStream.flush();
		}
		catch (final Exception e)
		{
			Cellngine.log(e, Constants.log_type.error);
			this.close();
			return false;
		}
		return true;
	}
	
	/**
	 * Instantly disconnects this socket.
	 */
	public void close()
	{
		try
		{
			this.socket.close();
		}
		catch (final Exception e)
		{
			Cellngine.log(e, Constants.log_type.error);
		}
	}
	
	/**
	 * @return Whether the connection is alive and can send and receive data.
	 */
	public boolean connectionAlive()
	{
		return !this.socket.isInputShutdown() && !this.socket.isOutputShutdown()
				&& !this.socket.isClosed();
	}
	
	public String getIPAddress()
	{
		return this.ip;
	}
}